package com.buddy.learn.spring.framework.webmvc.servlet;

import com.buddy.learn.spring.mvc.annotation.BRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class BHandlerAdapter {
    public boolean supports(Object handler) {
        return (handler instanceof BHandlerMapping);
    }

    public BModelAndView handle(HttpServletRequest req,
                                HttpServletResponse resp,
                                Object handler) throws Exception {
        BHandlerMapping handlerMapping = (BHandlerMapping) handler;
        //把方法的形参列表和request的参数列表所在顺序进行一一对应
        Map<String, Integer> paramIndexMapping = new HashMap<>();

        Annotation[][] pa = handlerMapping.getMethod().getParameterAnnotations();
        for (int i = 0; i < pa.length; i++) {
            for (Annotation a : pa[i]) {
                if (a instanceof BRequestParam) {
                    String paramName = ((BRequestParam) a).value();
                    if (!"".equals(paramName.trim())) {
                        paramIndexMapping.put(paramName, i);
                    }
                }
            }
        }

        //提取方法中的request和response参数
        Class<?>[] paramsTypes = handlerMapping.getMethod().getParameterTypes();
        for (int i = 0; i < paramsTypes.length; i++) {
            Class<?> type = paramsTypes[i];
            if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
                paramIndexMapping.put(type.getName(), i);
            }
        }


        //request中的形参列表
        Map<String, String[]> params = req.getParameterMap();
        //实参列表
        Object[] paramValues = new Object[pa.length];
        for (Map.Entry<String, String[]> param : params.entrySet()) {
            //如果是多个的话，就处理为一个
            String value = Arrays.toString(param.getValue())
                    .replaceAll("\\[|\\]", "")
                    .replaceAll("\\s", ",");
            if (!paramIndexMapping.containsKey(param.getKey())) {
                continue;
            }
            //得到参数的位置
            int index = paramIndexMapping.get(param.getKey());
            //request拿到的都是String
            paramValues[index] = caseStringValue(value, paramsTypes[index]);
        }

        if (paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
            int reqIndex = paramIndexMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex] = req;
        }

        if (paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
            int respIndex = paramIndexMapping.get(HttpServletResponse.class.getName());
            paramValues[respIndex] = resp;
        }
        Object result =
                handlerMapping.getMethod().invoke(handlerMapping.getControllers(), paramValues);
        if (result == null || result instanceof Void){

            return null;
        }
        //如果返回值本身就是modelAndView，则直接返回
        boolean isModelAndView = handlerMapping.getMethod().getReturnType() == BModelAndView.class;
        if (isModelAndView){
            return (BModelAndView) result;
        }

        return null;
    }

    //url传递过来的参数都是String类型的，HTTP是基于字符串协议
    //只需要把String转换为对应类型
    private Object caseStringValue(String value, Class<?> paramsType) {
        if (String.class == paramsType) {
            return value;
        }
        if (Integer.class == paramsType) {
            return Integer.valueOf(value);
        } else if (Double.class == paramsType) {
            return Double.valueOf(value);
        } else {
            if (value != null) {
                return value;
            }
            return null;
        }
        //如果还有其他类型，考虑使用策略模式了
    }

}
